package com.acme.chat.client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;

import com.acme.chat.message.ChatMessage;
import com.acme.chat.message.Message;
import com.acme.chat.message.MessageType;

// TODO: Refactor all this class
public class ClientGUI extends JFrame implements ActionListener {

    private static final String WINDOW_NAME = "Chat client";

    private static final String LABEL_SERVER = "Server";
    private static final String DEFAULT_HOST = "localhost";

    private static final String LABEL_PORT = "Port";
    private static final int DEFAULT_PORT = 6800;

    private static final String LABEL_LOGIN = "login";
    private static final String LABEL_LOGOUT = "logout";
    private static final String LABEL_LIST = "list";

    private static final String LABEL_ROOM = "Room";
    private static final String DEFAULT_ROOM = "1";

    private static final String LABEL_PRIVATE_NAME = "Private name";

    private static final String ERROR_EMPTY_NAME = "Error!\nYour name must contain at least one character.\n";
    private static final String ERROR_EMPTY_HOSTNAME = "Error!\nYou need to enter the address or server host name.\n";
    private static final String ERROR_EMPTY_PORT = "Error!\nYou need to enter the port number.\n";
    private static final String ERROR_PORT_FORMAT = "Error!\nYou need to enter valid port number.\n";

	private JLabel lServer, lPort, lRoom, label, lPrivateName;
	private JTextField tf;
	private JTextField tfServer, tfPort, tfRoom,tfPrivateName;
	private JButton login, logout, list;
	private JTextArea ta;
	private boolean connected;
	private Client client;
	private int defaultPort;
	private String defaultHost;

	private JPanel contentPane;

	/**
	 * Creates chat window.
	 *
	 * @param host
	 * @param port
	 */
	public ClientGUI(String host, int port) {
		super(WINDOW_NAME);

		defaultPort = port;
		defaultHost = host;

		this.setResizable(false);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(null);

		tfServer = new JTextField();
		tfServer.setText(DEFAULT_HOST);
		tfServer.setBounds(50, 11, 86, 20);
		contentPane.add(tfServer);
		tfServer.setColumns(10);

		lServer = new JLabel(LABEL_SERVER);
		lServer.setBounds(10, 14, 46, 14);
		contentPane.add(lServer);

		lPort = new JLabel(LABEL_PORT);
		lPort.setBounds(10, 49, 46, 14);
		contentPane.add(lPort);

		tfPort = new JTextField();
		tfPort.setText(String.valueOf(port));
		tfPort.setBounds(50, 46, 86, 20);
		contentPane.add(tfPort);
		tfPort.setColumns(10);

		lRoom = new JLabel(LABEL_ROOM);
		lRoom.setBounds(10, 89, 46, 14);
		contentPane.add(lRoom);

		tfRoom = new JTextField();
		tfRoom.setText(DEFAULT_ROOM);
		tfRoom.setBounds(50, 86, 86, 20);
		contentPane.add(tfRoom);
		tfRoom.setColumns(10);

		tf = new JTextField();
		tf.setBounds(192, 46, 361, 20);
		contentPane.add(tf);
		tf.setColumns(10);

		label = new JLabel("Enter your name");
		label.setHorizontalAlignment(SwingConstants.CENTER);
		label.setBounds(212, 14, 179, 14);
		contentPane.add(label);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(192, 78, 361, 127);
        contentPane.add(scrollPane);

        ta = new JTextArea();
        ta.setEditable(false);
        scrollPane.setViewportView(ta);

		lPrivateName = new JLabel(LABEL_PRIVATE_NAME);
		lPrivateName.setBounds(45, 150, 78, 29);
		contentPane.add(lPrivateName);

		tfPrivateName = new JTextField();
		tfPrivateName.setBounds(29, 185, 108, 20);
		contentPane.add(tfPrivateName);
		tfPrivateName.setColumns(10);

		login = new JButton(LABEL_LOGIN);
		login.addActionListener(this);
		login.setBounds(45, 232, 89, 23);
		contentPane.add(login);

		logout = new JButton(LABEL_LOGOUT);
		logout.addActionListener(this);
		logout.setBounds(180, 232, 89, 23);
		logout.setEnabled(false);
		contentPane.add(logout);

		list = new JButton(LABEL_LIST);
		list.addActionListener(this);
		list.setBounds(320, 232, 89, 23);
		list.setEnabled(false);
		contentPane.add(list);

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 590, 312);
		setVisible(true);
	}

    public ClientGUI() {
        this(DEFAULT_HOST, DEFAULT_PORT);
    }

	public void append(String str) {
		ta.append(str);
		ta.setCaretPosition(ta.getText().length() - 1);
	}

	void connectionFailed() {
		login.setEnabled(true);
		logout.setEnabled(false);
		list.setEnabled(false);
		label.setText("Enter your username below");
		tf.setText("");
		tfPort.setText("" + defaultPort);
		tfServer.setText(defaultHost);
		tfServer.setEditable(false);
		tfPort.setEditable(false);
		tf.removeActionListener(this);
	}

	// TODO: refactor this ...
	private Message processCommand(String text, String room) {
	    String[] commands = text.split("\\s+");
	    if (commands.length > 2) {
	        if ("/m".equals(commands[0]) || "/msg".equals(commands[0])) {
	            String nameTo = commands[1];
	            StringBuilder sb = new StringBuilder();
	            for (int i = 2; i < commands.length; i++) {
	                sb.append(commands[i]).append(" ");
	            }
	            Message message = new ChatMessage(MessageType.PRIVATE, sb.toString(), nameTo, room);
	            return message;
	        }
	    }

	    return null;
	}

	@Override
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if (o == logout) {
//            client.sendMessage(new ChatMessage(MessageType.LOGOUT, "", "", null));
            connected = false;
            return;
        }

        if (o == list) {
//            client.sendMessage(new ChatMessage(MessageType.WHOISIN, "", "", null));
            return;
        }

        if (connected) {
            String room = tfRoom.getText().trim();

            if (client.changeRoom(room)) {
//                client.sendMessage(new ChatMessage(MessageType.CHANGE_ROOM, "", "", client.getRoom()));
            }

            Message message = processCommand(tf.getText(), tfRoom.getText());

            if (message != null) {
//                client.sendMessage(message);
                tf.setText("");
                return;
            }

            if (tfPrivateName.getText().length() != 0) {
//                client.sendMessage(new ChatMessage(MessageType.PRIVATE, tf.getText(), tfPrivateName.getText(), room));
                tf.setText("");
                tfPrivateName.setText("");
            } else {
//                client.sendMessage(new ChatMessage(MessageType.MESSAGE, tf.getText(), "", room));
            }
            tf.setText("");
            return;
        }

		if (o == login) {
			String username = tf.getText().trim();
			String room = tfRoom.getText().trim();
			if (username.length() == 0){
			    append(ERROR_EMPTY_NAME);
			    return;
			}

			String server = tfServer.getText().trim();
			if (server.length() == 0) {
			    append(ERROR_EMPTY_HOSTNAME);
			    return;
			}

			String portNumber = tfPort.getText().trim();
			if (portNumber.length() == 0){
			    append(ERROR_EMPTY_PORT);
			    return;
			}

			int port = 0;
			try {
				port = Integer.valueOf(portNumber);
			} catch (NumberFormatException nfe) {
			    append(ERROR_PORT_FORMAT);
				return;
			}

			client = new Client(server, port, room, username, this);
			if (!client.start())
				return;
			tf.setText("");
			label.setText("Enter your message below");
			connected = true;
			login.setEnabled(false);
			logout.setEnabled(true);
			list.setEnabled(true);
			tfServer.setEditable(false);
			tfPort.setEditable(false);
			tf.addActionListener(this);
		}
	}

		public static void main(String[] args) {
			new ClientGUI("localhost", 6800);
		}
}